﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Passwords.Properties;
using System.Security.Principal;
using System.IO;
using System.Diagnostics;
using Passwords.Models;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using Passwords.ViewModels;

namespace Passwords.Services
{
    public static class ServiceUtil
    {
        public static string ServiceUri
        {
            get { return GetServiceUri(Settings.Default.Port); }
        }

        public static string RegisterPortAccessScript
        {
            get { return GetRegisterNetShAccessScript(Settings.Default.Port); }
        }

        public static string UnregisterPortAccessScript
        {

            get { return GetUnregisterNetShAccessScript(Settings.Default.Port); }
        }

        public static string GetServiceUri(int port)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("http://");
            sb.Append(Environment.MachineName);

            if (port != 80)
            {
                sb.Append(":");
                sb.Append(port);
            };
            sb.Append("/SyncService");
            return sb.ToString();
        }

        public static string GetRegisterNetShAccessScript(int port)
        {
            if (IsXP()) return string.Empty;
            string user = WindowsIdentity.GetCurrent().Name;
            return string.Format("netsh http add urlacl url=http://+:{0}/SyncService user={1}", port, user);
        }

        public static string GetUnregisterNetShAccessScript(int port)
        {
            if (IsXP()) return string.Empty;
            return string.Format("netsh http delete urlacl url=http://+:{0}/SyncService", port);
        }

        private static bool IsXP()
        {
            return Environment.OSVersion.Version.Major == 5;
        }

        public static string GetAddPortRuleScript(string appName)
        {
            if (IsXP())
            {
                // W2K, XP, W2003
                return string.Format("netsh firewall add portopening name=\"PasswordService\" scope=all  port={0} protocol=TCP enable", Settings.Default.Port);
            }
            else
            {
                if (string.IsNullOrEmpty(appName))
                {
                    return string.Format("netsh advfirewall firewall add rule name=\"PasswordService\" dir=in action=allow localport={0} protocol=TCP profile=private description=\"firewall rule for passwords in order to synchronize with windows phone 7.\"", Settings.Default.Port);
                }
                else
                {
                    return string.Format("netsh advfirewall firewall add rule name=\"PasswordService\" dir=in action=allow localport={0} protocol=TCP profile=private program={1} description=\"firewall rule for passwords in order to synchronize with windows phone 7.\"", Settings.Default.Port, appName);
                }
            }
        }

        public static string GetDeletePortRuleScript(string appName)
        {
            if (IsXP())
            {
                return string.Format("netsh  firewall delete portopening  port={0} protocol=TCP", Settings.Default.Port);
            }
            else
            {
                if (string.IsNullOrEmpty(appName))
                {
                    return string.Format("netsh advfirewall firewall remove rule name=\"PasswordService\" dir=in action=allow localport={0} protocol=TCP profile=private", Settings.Default.Port);
                }
                else
                {
                    return string.Format("netsh advfirewall firewall remove rule name=\"PasswordService\" dir=in action=allow localport={0} protocol=TCP program={1} profile=private", Settings.Default.Port, appName);
                }
            }
        }

        public static string GetFirewallText(string appName, int port)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(AppResources.SettingsFirewallText);

            return sb.ToString(); ;
        }

        public static void RegisterFirewall()
        {
            string tempPath = Path.GetTempPath();
            string tempExe = Path.Combine(tempPath, "PwsRegister.bat");
            string exePath = Environment.CommandLine;
            //string portOpening = ServiceUtil.GetAddPortRuleScript(exePath);
            string portOpening = ServiceUtil.GetAddPortRuleScript(null);


            try
            {
                using (FileStream fs = new FileStream(tempExe, FileMode.Create, FileAccess.Write))
                {
                    using (StreamWriter writer = new StreamWriter(fs))
                    {
                        writer.WriteLine(ServiceUtil.RegisterPortAccessScript);
                        writer.WriteLine(portOpening);
                    }
                }



                ProcessStartInfo psi = new ProcessStartInfo(tempExe);
                psi.UseShellExecute = true;
                psi.WorkingDirectory = tempPath;
                if (!ServiceUtil.IsXP()) psi.Verb = "runas";
                try
                {
                    Process process = Process.Start(psi);
                    process.WaitForExit();
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message);
                }
            }
            finally
            {
                File.Delete(tempExe);
            }
        }

        public static void UnregisterFirewall()
        {
            string tempPath = Path.GetTempPath();
            string tempExe = Path.Combine(tempPath, "PwsRegister.bat");
            string exePath = Environment.CommandLine;
            string portOpening = ServiceUtil.GetDeletePortRuleScript(exePath);


            try
            {
                using (FileStream fs = new FileStream(tempExe, FileMode.Create, FileAccess.Write))
                {
                    using (StreamWriter writer = new StreamWriter(fs))
                    {
                        writer.WriteLine(ServiceUtil.UnregisterPortAccessScript);
                        writer.WriteLine(portOpening);
                    }
                }

                ProcessStartInfo psi = new ProcessStartInfo(tempExe);
                psi.UseShellExecute = true;
                psi.WorkingDirectory = tempPath;
                if (!ServiceUtil.IsXP()) psi.Verb = "runas";
                try
                {
                    Process process = Process.Start(psi);
                    process.WaitForExit();
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
            }
            finally
            {
                File.Delete(tempExe);
            }
        }

        public static void EncryptFields(PasswordContract password, SymmetricAlgorithm aes)
        {
            if (password == null) throw new ArgumentNullException("password");

            DataContractSerializer serializer = new DataContractSerializer(typeof(FieldContract[]));
            FieldContract[] fc = password.Fields.ToArray();
            using (MemoryStream ms = new MemoryStream())
            {
                using (ICryptoTransform transform = aes.CreateEncryptor())
                {
                    using (Stream stream = new CryptoStream(ms, transform, CryptoStreamMode.Write))
                    {
                        serializer.WriteObject(stream, fc);
                    }
                }
                password.EncryptedDetails = ms.ToArray();

            }
        }

        public static IEnumerable<FieldContract> DecryptFields(PasswordContract password, SymmetricAlgorithm aes)
        {
            if (password == null) throw new ArgumentNullException("password");
            if (password.EncryptedDetails == null) return null;
            DataContractSerializer serializer = new DataContractSerializer(typeof(FieldContract[]));
            using (MemoryStream ms = new MemoryStream(password.EncryptedDetails))
            {
                ms.Position = 0;
                using (ICryptoTransform transform = aes.CreateDecryptor())
                {
                    using (Stream stream = new CryptoStream(ms, transform, CryptoStreamMode.Read))
                    {
                        FieldContract[] fc = serializer.ReadObject(stream) as FieldContract[];
                        return fc;
                    }
                }
            }
        }


    }
}
